<?php

namespace app\business\controller\api;

use app\admin\controller\api\Upload;
use app\data\service\UserService;
use app\devices\controller\Feedback;
use app\devices\service\BoxService;
use app\devices\service\DevicesService;
use app\devices\service\OrderService;
use app\devices\service\SocketService;
use app\wechat\service\FansService;
use think\admin\Service;
use think\App;
use think\cache\driver\Redis;
use think\facade\Db;

/**
 * 设备数据接口
 * Class Index
 * @package app\data\controller\api
 */
class Index extends Auth
{
    protected $redis;

    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->redis = new Redis();
    }

    public function upgradeTips(){
        $user = $this->user;

        $devices = $this->app->db->name('JcgDevices')->where('store_id', "in", $user['stores'])->column("device_id");

        $version = (int)str_replace(".","",sysconf('edition.versionName')??'1.0.0');
        $num = 0;
        foreach ($devices as $row){
            $dev_version = $this->redis->get("DevicesVersionName".$row);
            if((int)str_replace(".","",$dev_version)<$version){
                $num++;
            }
        }
        $this->success("成功", ['num'=>$num]);
    }

    /**
     * 获取首页聚合数据
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getHome(){
        $user = $this->user;

        if(isset($user['role_id']) && $user['role_id']!=1){
            $store_name = $user['nickname']??'';
        }else{
            $store_ids = is_array($user['stores'])?$user['stores']:explode(",",$user['stores']);

            $stores = DevicesService::instance()->getStore(current($store_ids));
            $store_name = $stores['name']??'';
        }

        //本月
        $month = OrderService::instance()->getInfos($user['stores'], [date("Y-m-01"), date("Y-m-t 23:59:59")]);

        $last_m = strtotime("-1 month");
        //上个月
        $last_month = OrderService::instance()->getInfos($user['stores'], [date("Y-m-01",$last_m), date("Y-m-t 23:59:59",$last_m)], true);

        //昨日
        $today = strtotime("-1 day");
        $yesterday = OrderService::instance()->getInfos($user['stores'], [date("Y-m-d", $today), date("Y-m-d 23:59:59", $today)],true);

        $this->success('成功', ['store_name'=>$store_name, 'stores'=>$user['stores'], 'month'=>$month, 'last_month'=>$last_month, 'yesterday'=>$yesterday]);
    }

    public function getStores(){
        $user = $this->user;

        $map[] = ['id', "in", $user['stores']];

        $query = $this->_query('JcgStore');
        $result = $query->like("name")->where($map)->field("id as store_id, name as store_name, contacts, contact_number, share_ratio, concat_ws(' ', area, address) as address, start_hours, end_hours, status")->order('id desc')->page(true, false, false, 10);

        $fees = $this->app->db->name("jcg_device_fee")->where("store_id", "in", $user['stores'])->column("store_id, fee_type","store_id");

        $fee_types = [3=>'按时收费', 2=>'按次收费', 1=>'免费'];

        foreach ($result['list'] as &$row){
            $row['hours'] = substr($row['start_hours'],0,5).' - '.substr($row['end_hours'],0,5);
            $row['share_ratio'] = ceil($row['share_ratio']).'%';
            $row['fee_type'] = $fee_types[$fees[$row['store_id']]['fee_type']??0]??'';
            $row['status'] = $row['status']?'营业中':'暂停营业';
            unset($row['start_hours'], $row['end_hours']);
        }

        unset($user);

        $this->success("成功", $result);
    }

    /**
     * 获取商户所有柜子
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getDevices(){
        $user = $this->user;

        $map[] = ['store_id', "in", $user['stores']];
        if(isset($user['role_id']) && $user['role_id']!=1){
            $data = $this->_vali(
                [
                    'store_id.require' => '柜点ID不可为空！',
                ]
            );
            $map = ['store_id'=>$data['store_id']];
        }

        $query = $this->_query('JcgDevices');
        $result = $query->like("device_no")->where($map)->field("id as d_id, device_name, device_no, online, status, device_id, online")->order('id desc')->page(true, false, false, 10);

        DevicesService::instance()->getBoxInfo($result['list'], $user);
        unset($user);

        $this->success("成功", $result);
    }

    /**
     * 刷新箱子在线状态
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function flushOnline(){

        $socket = new SocketService($this->app);

        $device_ids = $this->app->db->name('jcg_devices')->where("store_id", 'in',$this->user['stores'])->column("device_id");

        foreach ($device_ids as $row){
            $msg = ['type'=>1, 'device_id'=>$row, 'device_board'=>'00'];
            $socket->sendSocket($msg);
        }
        $this->success("指令已发送");
    }

    /**
     * 获取箱格信息
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getBoxs(){
        $data = $this->_vali(
            [
                'd_id.require' => '设备ID不可为空！',
            ]
        );

        if(!isset($this->user['devices'][$data['d_id']])){
            $this->error("权限不足");
        }

        $result['device_name'] = $this->user['devices'][$data['d_id']]['device_name'];
        $result['tips'] = '点击箱格编号可开门';

        $query = $this->_query('JcgBoxs')->equal("d_id");

        $list = $query->field("id as box_id, box_num, is_lock, box_status, user_type")->order('box_num asc')->page(false, false);

        foreach ($list['list'] as &$row){
            $row['box_num'] = $row['box_num']<10?'0'.$row['box_num']:$row['box_num'];
        }

        BoxService::instance()->buildBoxList($list['list'], $this->user);

        $result['list'] = $list['list'];

        $this->success("获取箱门数据成功", $result);
    }

    /**
     * 刷新箱格锁状态
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function flush(){
        $data = $this->_vali(
            [
                'd_id.require' => '设备ID不可为空！',
            ]
        );
        if($this->redis->get("clickFlush".$this->uuid)){
            $this->error("请等待8秒执行命令");
        }

        if(!isset($this->user['devices'][$data['d_id']])){
            $this->error("权限不足");
        }

        $this->redis->set("clickFlush".$this->uuid, 1, 8);

        $socket = new SocketService($this->app);

        $device = DevicesService::instance()->getDevice($data['d_id']);

        $boards = $this->app->db->name("jcg_boxs")->where("d_id", $data['d_id'])->group("device_board")->column("device_board");
        foreach ($boards as $row){
            $msg = ['type'=>1, 'device_id'=>$device['device_id'], 'device_board'=>$row];
            $socket->sendSocket($msg);
        }
        $this->success("指令已发送");
    }

    /**
     * 获取订单列表
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function orderList(){
        $data = $this->_vali([
            'status.default'=>0,
            'title.default'=>'',
            's_type.default'=>1,
            'page.default'=>1,
        ]);

        $map = [['store_id', 'in', $this->user['stores']], ['deleted', '=', 0]];

        $day_start = strtotime(date("Y-m-d"));
        $day_end = strtotime(date("Y-m-d").' 23:59:59');
        switch ($data['s_type']){
            case 1:
                $map[] = ['create_time', "between", [$day_start, $day_end]];
                break;
            case 2:
                $map[] = ['create_time', "between", [strtotime('-1 day', $day_start), strtotime('-1 day',$day_end)]];
                break;
            case 3:
                $map[] = ['create_time', "between", [strtotime('-7 day', $day_start), strtotime('-1 day',$day_end)]];
                break;
            case 4:
                $map[] = ['create_time', "between", [strtotime('-30 day', $day_start), strtotime('-1 day',$day_end)]];
                break;
            case 5:
                $map[] = ['create_time', "between", [strtotime('-365 day', $day_start), strtotime('-1 day',$day_end)]];
                break;
            default:
                break;
        }

        $wh = "1=1";
        if($data['status'] && !in_array($data['status'], [1,2,3])){
            $this->error('订单状态输入有误');
        }else if($data['status']){
            if($data['status']==3){
                $wh = "out_times=1 AND status=1";
            }else if($data['status']==1){
                $wh = "out_times=0 AND status=1";
            }else{
                $wh = "status=".$data['status'];
            }
        }

        $map_str = "1=1";
        if($data['title']){
            $map_str = "extends like '%\"box_num\":".$data['title'].",%'";
            $uids = $this->app->db->name("data_user")->where("nickname|phone", "=", $data['title'])->column("id");
            if($uids){
                $map_str .= count($uids)>1?' OR user_id in ('.implode(",",$uids).')':" OR user_id=".$uids[0];
            }
        }

        $field = "id, order_no, create_time, reality_end_time, money, extends, s_id, status, user_id, box_id, fee_type, out_times";

        $query = $this->_query('JcgDevicesOrder')->equal('order_no');
        $result = $query->field($field)->whereRaw($wh)->where($map)->whereRaw($map_str)->order('id desc')
            ->page(true, false, false, 10);
        if (count($result['list']) > 0) OrderService::instance()->buildOrderList($result['list']);

        $this->success('获取订单数据成功！', $result);
    }

    /**
     * 开箱
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function unlock(){
        $data = $this->_vali(
            [
                'box_id.require' => '箱子ID不能为空！',
                'order_id.default' => 0,
            ]
        );

        $res = $this->redis->get("BClickUnlock".$this->uuid);
        if($res){
            $this->error("点击过快");
        }
        $this->redis->set("BClickUnlock".$this->uuid, 1,3);

        $devices = $this->user['devices']??[];
        if(empty($devices)){
            $devices = $this->user['devices'] = DevicesService::instance()->getStoresDevices($this->user['stores']);
            $this->redis->set("sys_store_user_".$this->uuid, $this->user, 7200);
        }
        $d_ids = array_keys($devices);

        $box = BoxService::instance()->getBox($data['box_id'], [['d_id', 'in', $d_ids]]);
        if(empty($box)){
            $this->error("箱格不存在");
        }

        if($box['box_status']>2){
            $this->error("箱格处于".BoxService::instance()->box_status[$box['box_status']].'状态');
        }else if($box['is_lock']<1){
            $this->error("箱门已打开");
        }else if($box['is_lock']==2){
            $this->error("箱格锁异常");
        }

        if($data['order_id']<1){
            $device_id = $devices[$box['d_id']]['device_id'];
            $msg = ['type'=>2, 'device_id'=>$device_id, 'ch'=>$box['board_channel'], 'device_board'=>$box['device_board']];
            SocketService::instance()->sendSocket($msg);

            $this->success("成功");
        }

        $map = [['id', "=", $data['order_id']], ['store_id', 'in', $this->user['stores']]];
        $order = OrderService::instance()->get('', $map);
        if (empty($order)) $this->error('读取订单失败');

        $this->app->db->startTrans();
        try{
            $extends = json_decode($order['extends'], true);
            $extends['ip'] = $this->app->request->ip();

            $out_money = 0;
            if($order['fee_type']==3){
                $re_amount = ceil((time()-$order['create_time']-$order['free_hours']*3600)/3600)*$order['amount'];
                $re_amount = $re_amount>0?$re_amount:0;
                if(in_array($order['store_id'], OrderService::instance()->special_store) && $re_amount){
                    $re_amount = $re_amount<2?2:$re_amount;
                }
                $out_money = OrderService::instance()->getRefund($order);
                $max_money = $extends['max_money']??0;
                if($re_amount>$max_money){
                    $re_amount = $max_money;
                }
                if($order['money']<$re_amount && !$out_money){

                }else{
                    $order['refund'] = $order['money']-$re_amount;
                }
            }

            $res = 1;
            $s_data['reality_end_time'] = time();
            $s_data['status'] = 2;
            $s_data['s_id'] = $this->uuid;

            if($order['fee_type']==3){
                if($order['refund']>0){
                    $refund = OrderService::instance()->refund($order);
                    if(is_array($refund)){
                        $s_data['out_refund_no'] = $refund['out_refund_no'];
                        if(empty($refund['out_refund_no'])){
                            $extends['refund_error'] = $refund['err_code_des'];
                        }
                    }
                    $s_data['amount_total'] = $order['money']-$order['refund']+$out_money;
                }else{
                    $s_data['amount_total'] = $order['money']+$out_money;
                }
            }else{
                $s_data['amount_total'] = $order['money'];
            }

            $s_data['extends'] = json_encode($extends, 256);

            $res_a = DevicesService::instance()->usePickUpCode(['box_id'=>$order['box_id'], 'order_id'=>$data['order_id'], 'user_id'=>$order['user_id']]);
            $res1 = OrderService::instance()->endOrder($order['id'], $s_data);
            $res2 = BoxService::instance()->updateBox($order['box_id'], ['box_status'=>1, 'user_id'=>0]);

            if($res_a && $res1 && $res2){
                $order['reality_end_time'] = $s_data['reality_end_time'];
                $order['status'] = $s_data['status'];

                $openid2 = UserService::instance()->getOpenid($order['user_id']);
                if($openid2){
                    OrderService::instance()->sendTemp(2, $openid2, [$devices[$box['d_id']]['device_name'], ($box['box_num']<10?'0'.$box['box_num']:$box['box_num']).'号', sprintf("%.2f", $s_data['amount_total']).'元', date("Y-m-d H:i", $order['create_time']), date("Y-m-d H:i")],'','感谢你的使用！如有物品未取，请联系：'.($extends['store_contact']??''));
                }

                $this->app->db->commit();
            }else{
                $this->app->db->rollback();
                $this->error("失败");
            }

            if($res){
                $device_id = $devices[$box['d_id']]['device_id'];
                $msg = ['type'=>2, 'device_id'=>$device_id, 'ch'=>$order['board_channel'], 'device_board'=>$order['device_board']];
                SocketService::instance()->sendSocket($msg);

                //删除超时定时任务对应订单缓存
                OrderService::instance()->clearOutTimeOrderCache($order);

                //移除已使用的箱子ID
                $this->redis->handler()->ZREM("orderUseBox".$order['d_id'], $order['box_id']);
            }else{
                $this->error("失败");
            }
        }catch (\Exception $e){
            $this->error("失败：".$e->getMessage());
        }

        jcgoplog('开锁','商户中心开锁', $this->user['nickname'],0,$order['id'], $order['box_id']);

        $this->redis->delete("BClickUnlock".$this->uuid);
        $this->success('成功');
    }

    /**
     * 开启所有箱格
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function unlockAll(){
        $data = $this->_vali(
            [
                'd_id.require' => '设备ID不能为空！',
            ]
        );
        $this->error("功能调整，暂时关闭");

        $res = $this->redis->get("BClickUnlockAll");
        if($res>0){
            $this->error("点击过快");
        }
        $this->redis->set("BClickUnlockAll", 1,3);

        if(!isset($this->user['devices'][$data['d_id']])){
            $this->error("权限不足");
        }

        $device = DevicesService::instance()->getDevice($data['d_id']);
//        $msg = ['type'=>4, 'device_id'=>$device['device_id']];

        $boxs = $this->app->db->name("jcg_boxs")->where([['d_id','=',$data['d_id']], ['user_type','=',0]])->order("box_num ASC")->column("device_board, board_channel",'id');
        foreach ($boxs as $row){
            $msg = ['type'=>2, 'device_id'=>$device['device_id'],  'ch'=>$row['board_channel'], 'device_board'=>$row['device_board']];
            SocketService::instance()->sendSocket($msg, 5);
        }


        $this->success('成功发送开箱命令');
    }

    /**
     * 订单统计
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function finance(){
        $data = $this->_vali([
            's_type.default'=>1,
            'page.default'=>1,
        ]);

        $user = $this->user;

        $map = [['store_id', 'in', $this->user['stores']], ['deleted', '=', 0], ['status', '=', 2]];

        switch ($data['s_type']){
            case 1:
                $format = 'DATE(create_at)';
                break;
            case 2:
                $format = 'MONTH(create_at)';
                break;
            default:
                $format = 'YEAR(create_at)';
                break;
        }

        $role_id = isset($user['role_id']) && $user['role_id']?$user['role_id']:1;
        $group = $role_id!=1?'store_id,time':"d_id, time";
        $order = "time DESC";

        $limits = $this->app->db->name('JcgDevicesOrder')->where($map)->group($group)->column('DATE_FORMAT(FROM_UNIXTIME(create_time), '.$format.') as time');
        $total = count($limits);

        $limit = $this->app->request->get('limit', $this->app->cookie->get('limit',10));
        $page = $data['page'];

        $subSql = $this->app->db->name("JcgDevicesOrder")->where($map)->field("id, ".$format." as time, `status`, d_id, store_id, IF(fee_type=3,amount_total*share_ratio,money*share_ratio) as amount, IF(fee_type=3,amount_total,money) as amount_a, extends, create_time")->buildSql();

        $list = Db::query("SELECT d_id, store_id, create_time, COUNT(IF(amount_a>0,id,NULL)) as num, sum(amount_a) as total, time, extends FROM {$subSql} a GROUP BY ".$group." ORDER BY ".$order." limit ".($page-1)*$limit.",".$limit);

        foreach ($list as &$row){
            if($data['s_type']==2){
                $row['time'] = date("Y-",$row['create_time']). ($row['time']<10?'0'.$row['time']:$row['time']);
            }
            $extends = json_decode($row['extends'], true);
            $device_name = explode(" ", $extends['device_name']);
            $row['device_name'] = $device_name[0];
            $row['device_no'] = $role_id==1?$device_name[1]:"";
            unset($row['extends']);
        }

        $result = [
            'page' => [
                'limit' => $limit,
                'total' => $total,
                'pages' => ceil($total/$limit),
                'current' => $page,
            ],
            'list' => $list,
        ];

        $this->success("成功", $result);
    }

    /**
     * 关于我们
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function about(){
        $user = $this->user;

        if(isset($user['role_id']) && $user['role_id']!=1){
            $store_name = $user['nickname']??'';
        }else{
            $store_ids = is_array($user['stores'])?$user['stores']:explode(",",$user['stores']);

            $stores = DevicesService::instance()->getStore(current($store_ids));
            $store_name = $stores['name']??'';
        }
        $result = [
            'logo'=>sysconf('edition.business_logo'),
            'sys_name'=>sysconf('contact.name'),
            'version'=>sysconf('edition.version'),
            'wx_app_name'=>sysconf('contact.app_name'),
            'business_phone'=>sysconf('contact.phone'),
            'store_name'=>$store_name,
        ];
        $this->success("成功", $result);
    }

    /**
     * 上传文件
     * @return \think\response\Json
     * @throws \think\admin\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function upload(){
        set_time_limit (600);
        ini_set('max_execution_time', 600);
        $upload = new Upload($this->app);
        $file = $this->request->file();
        if(empty($file)){
            $this->error("上传文件不存在");
        }
        return $upload->file();
    }

    /**
     * 获取
     * @throws \think\Exception
     * @throws \think\admin\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function state(){
        $this->_vali(
            [
                'name.require' => '文件名不能为空',
                'uptype.require' => '类型不能为空',
                'xkey.require' => '文件md5不能为空',
            ]
        );
        set_time_limit (600);
        ini_set('max_execution_time', 600);
        $upload = new Upload($this->app);
        return $upload->state();
    }

    /**
     * 意见反馈
     */
    public function feedBack(){
        $redis = new Redis();
        $data = $this->_vali(
            [
                'contents.default' => '',
                'files.default' => '',
                'feed_type.require' => '',
                'username.require' => '',
                'rank.require' => '',
                'is_reply.require' => '',
                'replay_summary.default'=>''
            ]
        );
        if($redis->get("feedBack".$this->uuid)){
            $this->error("点击过快");
        }

        if(empty($data['contents']) && empty($data['files'])){
            $this->error("反馈内容不能为空");
        }
        $data['user_id'] = $this->uuid;
        $data['user_type'] = 2;
        $res =  $this->app->db->name("jcg_feedback")->insert($data);
        if($res){
            $redis->set("feedBack".$this->uuid, 1,5);
            $this->success("成功");
        }else{
            $this->error('失败');
        }
    }

    public function feedList(){
        $query = $this->_query('jcg_feedback');
        $result = $query->like("device_no")->where('user_id', $this->uuid)->field("username,rank,feed_type,is_reply,replay_summary,contents,files,status,create_time")->order('id desc')->page(true, false, false, 10);

        $status_arr = ['未解决','解决中','已解决'];

        foreach ($result['list'] as &$row){
            $row['files'] = $row['files']?explode(",", $row['files']):[];

            $row['contents'] = str_replace(PHP_EOL,"<br/>", $row['contents']);
            
            $reg = "/#.*?#/";
            preg_match_all($reg, $row['contents'], $matches);
            $row['reply_content'] = [];
            if($matches){
                $row['reply_content'] = str_replace("#","", $matches[0]);
            }
            $row['contents'] = stripos($row['contents'],"#")?substr($row['contents'],0, stripos($row['contents'],"#")):$row['contents'];
//            $row['status'] = $status_arr[$row['status']];
            $row['create_time'] = date("Y-m-d H:i",strtotime($row['create_time']));
        }

        $this->success("成功", $result);
    }

    //修改密码
    public function changePwd(){
        $data = $this->_vali(
            [
                'old_pwd.require' => '旧密码不能为空',
                'pwd.require' => '新密码不能为空',
                'pwd.min:4'   => '新密码最少4位字符',
            ]
        );

        $map = ['id' => $this->uuid, 'is_deleted' => '0'];
        $user = $this->app->db->name('SystemUser')->where($map)->order('id desc')->find();
        if ($user['password'] !== $data['old_pwd']) {
            $this->error('旧密码错误，请重新输入!');
        }

        if ($data['old_pwd']==$data['pwd']){
            $this->error('新旧密码相同!');
        }

        if (strlen($data['pwd'])!=32){
            $this->error('请输入加密后的md5密码!');
        }

        if (data_save('SystemUser', ['id' => $this->uuid, 'password' => $data['pwd']], 'id')) {
            sysoplog('商户修改密码', "修改[{$user['id']}]密码成功");
            $redis = new Redis();
            $redis->delete("sys_store_user_".$user['id']);
            UserService::instance()->token(intval($user['id']), UserService::APITYPE_WAP);
            $this->success('密码修改成功，请使用新密码登录！');
        } else {
            $this->error('密码修改失败，请稍候再试！');
        }
    }

    /**
     * 退出登录
     * @throws \think\db\exception\DbException
     */
    public function logout(){
        $this->app->db->name('system_user_token')->where(['uid'=>$this->uuid])->delete();
        $this->redis->delete("sys_store_user_".$this->uuid);

        $this->success("成功");
    }
}